(* -*- sml -*- *)
(**
 * @copyright (C) 2021 SML# Development Team.
 * @author UENO Katsuhiro
 *)
structure ANormal =
struct

  type loc = Loc.loc

  (*%
   * @formatter(RuntimeCalc.ty) RuntimeCalc.format_ty
   *)
  (*% @prefix formatWithType_
   * @formatter(RuntimeCalc.ty) RuntimeCalc.formatWithType_ty
   *)
  type ty =
      (*% @format(ty) ty *)
      (*% @prefix formatWithType_ @format(ty) ty *)
      RuntimeCalc.ty

  (*%
   * @formatter(RuntimeCalc.varInfo) RuntimeCalc.format_varInfo
   *)
  (*% @prefix formatWithType_
   * @formatter(RuntimeCalc.varInfo) RuntimeCalc.formatWithType_varInfo
   *)
  type varInfo =
      (*% @format(x) x *)
      (*% @prefix formatWithType_ @format(x) x *)
      RuntimeCalc.varInfo

  (*%
   * @formatter(RuntimeCalc.ncconst) RuntimeCalc.format_ncconst
   *)
  (*% @prefix formatWithType_
   * @formatter(RuntimeCalc.ncconst) RuntimeCalc.formatWithType_ncconst
   *)
  datatype anconst = datatype RuntimeCalc.ncconst

  (*%
   *)
  (*% @prefix formatWithType_
   *)
  datatype anvalue =
      (*% @format({const, ty}) const *)
      (*% @prefix formatWithType_
       * @format({const, ty})
       * L2{ const +d ":" +1 ty }
       *)
      ANCONST of {const: anconst, ty: ty}
    | (*% @format(varInfo) varInfo *)
      (*% @prefix formatWithType_ @format(varInfo) varInfo *)
      ANVAR of varInfo
    | (*%
       * @format({exp, expTy, targetTy})
       * "cast" "(" !N0{ exp ")" }
       *)
      (*%
       * @prefix formatWithType_
       * @format({exp, expTy, targetTy})
       * "cast" "(" !L2{ exp +1 ":" +d targetTy} ")"
       *)
      ANCAST of
      {
        exp : anvalue,
        expTy : ty,
        targetTy : ty
      }
    | (*% @format "_" *)
      (*% @prefix formatWithType_ @format "_" *)
      ANBOTTOM

  (*%
   *)
  (*% @prefix formatWithType_
   *)
  datatype address =
      (*%
       * @format(ptrExp)
       * "[" +d "ptr" +d ptrExp "]"
       *)
      (*% @prefix formatWithType_
       * @format(ptrExp)
       * "[" +d "ptr" +d ptrExp "]"
       *)
      AAPTR of anvalue
    | (*%
       * @format({recordExp, fieldIndex})
       * "[" !N0{
       *   L2{ "#" +d fieldIndex }
       *   +1 "of"
       *   +1 recordExp
       * } "]"
       *)
      (*%
       * @prefix formatWithType_
       * @format({recordExp, fieldIndex})
       * "[" !N0{
       *   L2{ "#" +d fieldIndex }
       *   +1 "of"
       *   +1 recordExp
       * } "]"
       *)
      AARECORDFIELD of
      {
        recordExp : anvalue,
        fieldIndex : anvalue
      }
    | (*%
       * @format({arrayExp, elemSize, elemIndex})
       * "[" !N0{
       *   elemIndex
       *   +1 "*s" +d elemSize
       *   +1 "of"
       *   +1 arrayExp
       * } "]"
       *)
      (*%
       * @prefix formatWithType_
       * @format({arrayExp, elemSize, elemIndex})
       * "[" !N0{
       *   elemIndex
       *   +1 "*s" +d elemSize
       *   +1 "of"
       *   +1 arrayExp
       * } "]"
       *)
      AAARRAYELEM of
      {
        arrayExp : anvalue,
        elemSize : anvalue,
        elemIndex : anvalue
      }

  (*%
   *)
  (*% @prefix formatWithType_
   *)
  datatype initField =
      (*%
       * @format(exp) exp
       *)
      (*%
       * @prefix formatWithType_
       * @format(exp) exp
       *)
      INIT_VALUE of anvalue
    | (*%
       * @format({srcExp, fieldSize})
       * L8{ 1[
       *  "_init_copy"
       *  +1 srcExp
       *  +1 fieldSize
       * ] }
       *)
      (*%
       * @prefix formatWithType_
       * @format({srcExp, fieldSize})
       * L8{ 1[
       *  "_init_copy"
       *  +1 srcExp
       *  +1 fieldSize
       * ] }
       *)
      INIT_COPY of {srcExp: anvalue, fieldSize: anvalue}
    | (*%
       * @format({tagExp, tagOfTy, ifBoxed, ifUnboxed})
       * !R1{
       *   { "_init_if" 1[ +1 tagExp ] }
       *   +1 { "_when_boxed" 1[ +1 ifBoxed ] }
       *   +1 { "_when_unboxed" 1[ +1 ifUnboxed ] }
       * }
       *)
      (*%
       * @prefix formatWithType_
       * @format({tagExp, tagOfTy, ifBoxed, ifUnboxed})
       * !R1{
       *   { "_init_if" 1[ +1 tagExp ] }
       *   +1 { "_when_boxed" 1[ +1 ifBoxed ] }
       *   +1 { "_when_unboxed" 1[ +1 ifUnboxed ] }
       * }
       *)
      INIT_IF of {tagExp: anvalue, tagOfTy: Types.ty,
                  ifBoxed: initField, ifUnboxed: initField}

  (*%
   * @formatter(RuntimeCalc.primInfo) RuntimeCalc.format_primInfo
   * @formatter(ExtraDataLabel.id) ExtraDataLabel.format_id
   * @formatter(ExternSymbol.id) ExternSymbol.format_id
   * @formatter(CallbackEntryLabel.id) CallbackEntryLabel.format_id
   * @formatter(FunLocalLabel.id) FunLocalLabel.format_id
   * @formatter(HandlerLabel.id) HandlerLabel.format_id
   * @formatter(appList) TermFormat.formatAppList
   * @formatter(enclosedList) TermFormat.formatEnclosedList
   * @formatter(caseList) TermFormat.formatCaseList
   * @formatter(option) TermFormat.formatOptionalOption
   * @formatter(RuntimeCalc.calling_convention)
   *   RuntimeCalc.format_calling_convention
   * @formatter(bool) SmlppgUtil.formatBinaryChoice
   *)
  (*% @prefix formatWithType_
   * @formatter(RuntimeCalc.primInfo) RuntimeCalc.formatWithType_primInfo
   * @formatter(ExtraDataLabel.id) ExtraDataLabel.format_id
   * @formatter(ExternSymbol.id) ExternSymbol.format_id
   * @formatter(CallbackEntryLabel.id) CallbackEntryLabel.format_id
   * @formatter(FunLocalLabel.id) FunLocalLabel.format_id
   * @formatter(HandlerLabel.id) HandlerLabel.format_id
   * @formatter(appList) TermFormat.formatAppList
   * @formatter(enclosedList) TermFormat.formatEnclosedList
   * @formatter(caseList) TermFormat.formatCaseList
   * @formatter(option) TermFormat.formatOptionalOption
   * @formatter(RuntimeCalc.calling_convention)
   *   RuntimeCalc.formatWithType_calling_convention
   * @formatter(bool) SmlppgUtil.formatBinaryChoice
   *)
  datatype anexp =
      (*%
       * @format({resultVar, dataLabel, nextExp, loc})
       * L8{ resultVar +d "=" 1[
       *   +1 "largeint"
       *   +1 dataLabel
       *   ";"
       * ] }
       * +1 nextExp
       *)
      (*% @prefix formatWithType_
       * @format({resultVar, dataLabel, nextExp, loc})
       * L8{ resultVar +d "=" 1[
       *   +1 "largeint"
       *   +1 dataLabel
       *   ";"
       * ] }
       * +1 nextExp
       *)
      ANINTINF of
      {
        resultVar: varInfo,
        dataLabel: ExtraDataLabel.id,
        nextExp: anexp,
        loc : loc
      }
    | (*%
       * @format({resultVar: var varOpt, funExp, attributes,
       *          argExpList: arg args, nextExp, handler: handle handleOpt,
       *          loc})
       * L8{ varOpt(var)(, +d "=") 1[
       *   +1 "_ffiapply"
       *   +1 funExp
       *   +1 args:appList(arg)("(",",",")")
       *   handleOpt(handle)(+1 "handle" +d,)
       *   ";"
       * ] }
       * +1 nextExp
       *)
      (*% @prefix formatWithType_
       * @format({resultVar: var varOpt, funExp, attributes,
       *          argExpList: arg args, nextExp, handler: handle handleOpt,
       *          loc})
       * L8{ varOpt(var)(, +d "=") 1[
       *   +1 "_ffiapply"
       *   +1 funExp
       *   +1 args:appList(arg)("(",",",")")
       *   handleOpt(handle)(+1 "handle" +d,)
       *   ";"
       * ] }
       * +1 nextExp
       *)
      ANFOREIGNAPPLY of
      {
        resultVar : varInfo option,
        funExp : anvalue,
        argExpList : anvalue list,
        attributes : FFIAttributes.attributes,
        handler : HandlerLabel.id option,
        nextExp : anexp,
        loc : loc
      }
    | (*%
       * @format({resultVar, instTyvars, codeExp, closureEnvExp, nextExp, loc})
       * L8{ resultVar +d "=" 1[
       *   +1 "_exportcallback"
       *   +1 codeExp
       *   +1 closureEnvExp
       *   ";"
       * ] }
       * +1 nextExp
       *)
      (*% @prefix formatWithType_
       * @format({resultVar, instTyvars, codeExp, closureEnvExp, nextExp, loc})
       * L8{ resultVar +d "=" 1[
       *   +1 "_exportcallback"
       *   +1 codeExp
       *   +1 closureEnvExp
       *   ";"
       * ] }
       * +1 nextExp
       *)
      ANEXPORTCALLBACK of
      {
        resultVar : varInfo,
        codeExp : anvalue,
        closureEnvExp : anvalue,
        instTyvars : Types.btvEnv,
        nextExp : anexp,
        loc : loc
      }
    | (*%
       * @format({resultVar, id, nextExp, loc})
       * L8{ resultVar +d "=" 1[
       *   +1 "exvar"
       *   +1 "@ext:" id
       *   ";"
       * ] }
       * +1 nextExp
       *)
      (*% @prefix formatWithType_
       * @format({resultVar, id, nextExp, loc})
       * L8{ resultVar +d "=" 1[
       *   +1 "exvar"
       *   +1 "@ext:" id
       *   ";"
       * ] }
       * +1 nextExp
       *)
      ANEXVAR of
      {
        resultVar : varInfo,
        id: ExternSymbol.id,
        nextExp : anexp,
        loc : loc
      }
    | (*%
       * @format({resultVar, exp, expTy, nextExp, loc})
       * L8{ resultVar +d "=" 1[
       *   +1 "pack"
       *   +1 exp
       *   ";"
       * ] }
       * +1 nextExp
       *)
      (*% @prefix formatWithType_
       * @format({resultVar, exp, expTy, nextExp, loc})
       * L8{ resultVar +d "=" 1[
       *   +1 "pack"
       *   +1 exp
       *   ";"
       * ] }
       * +1 nextExp
       *)
      ANPACK of
      {
        resultVar : varInfo,
        exp : anvalue,
        expTy: ty,
        nextExp : anexp,
        loc : loc
      }
    | (*%
       * @format({resultVar, exp, nextExp, loc})
       * L8{ resultVar +d "=" 1[
       *   +1 "unpack"
       *   +1 exp
       *   ";"
       * ] }
       * +1 nextExp
       *)
      (*% @prefix formatWithType_
       * @format({resultVar, exp, nextExp, loc})
       * L8{ resultVar +d "=" 1[
       *   +1 "unpack"
       *   +1 exp
       *   ";"
       * ] }
       * +1 nextExp
       *)
      ANUNPACK of
      {
        resultVar : varInfo,
        exp : anvalue,
        nextExp : anexp,
        loc : loc
      }
    | (*%
       * @format({resultVar, srcAddr, valueSize, nextExp, loc})
       * L8{ resultVar +d "=" 1[
       *   +1 "dup"
       *   +1 srcAddr
       *   +1 valueSize
       *   ";"
       * ] }
       * +1 nextExp
       *)
      (*% @prefix formatWithType_
       * @format({resultVar, srcAddr, valueSize, nextExp, loc})
       * L8{ resultVar +d "=" 1[
       *   +1 "dup"
       *   +1 srcAddr
       *   +1 valueSize
       *   ";"
       * ] }
       * +1 nextExp
       *)
      ANDUP of
      {
        resultVar : varInfo,
        srcAddr : address,
        valueSize : anvalue,
        nextExp : anexp,
        loc : loc
      }
    | (*%
       * @format({resultVar, srcAddr, nextExp, loc})
       * L8{ resultVar +d "=" 1[
       *   +1 "load"
       *   +1 srcAddr
       *   ";"
       * ] }
       * +1 nextExp
       *)
      (*% @prefix formatWithType_
       * @format({resultVar, srcAddr, nextExp, loc})
       * L8{ resultVar +d "=" 1[
       *   +1 "load"
       *   +1 srcAddr
       *   ";"
       * ] }
       * +1 nextExp
       *)
      ANLOAD of
      {
        resultVar : varInfo,
        srcAddr: address,
        nextExp : anexp,
        loc : loc
      }
    | (*%
       * @format({resultVar, primInfo, argExpList: arg args, argTyList,
       *          resultTy,
       *          instTyList: ty tys,
       *          instTagList: tag tags, instSizeList: size sizes,
       *          nextExp, loc})
       * L8{ resultVar +d "=" 1[
       *   +1 "prim"
       *   +1 L2{ primInfo
       *          +1 "/t" +d tags:appList(tag)("(",",",")")
       *          +1 "/s" +d sizes:appList(size)("(",",",")") }
       *   +1 args:appList(arg)("(",",",")")
       *   ";"
       * ] }
       * +1 nextExp
       *)
      (*%
       * @prefix formatWithType_
       * @format({resultVar, primInfo, argExpList: arg args, argTyList,
       *          resultTy,
       *          instTyList: ty tys,
       *          instTagList: tag tags, instSizeList: size sizes,
       *          nextExp, loc})
       * L8{ resultVar +d "=" 1[
       *   +1 "prim"
       *   +1 L2{ primInfo
       *          +1 "/t" +d tags:appList(tag)("(",",",")")
       *          +1 "/s" +d sizes:appList(size)("(",",",")") }
       *   +1 args:appList(arg)("(",",",")")
       *   ";"
       * ] }
       * +1 nextExp
       *)
      ANPRIMAPPLY of
      {
        resultVar : varInfo,
        primInfo : RuntimeCalc.primInfo,
        argExpList : anvalue list,
        argTyList : ty list,
        resultTy : ty,
        instTyList : ty list,
        instTagList : anvalue list,
        instSizeList : anvalue list,
        nextExp : anexp,
        loc : loc
      }
    | (*%
       * @format({resultVar, exp, expTy, targetTy, nextExp, loc})
       * L8{ resultVar +d "=" 1[
       *   +1 "bitcast"
       *   +1 exp
       *   ";"
       * ] }
       * +1 nextExp
       *)
      (*% @prefix formatWithType_
       * @format({resultVar, exp, expTy, targetTy, nextExp, loc})
       * L8{ resultVar +d "=" 1[
       *   +1 "bitcast"
       *   +1 exp
       *   ";"
       * ] }
       * +1 nextExp
       *)
      ANBITCAST of
      {
        resultVar : varInfo,
        exp : anvalue,
        expTy : ty,
        targetTy : ty,
        nextExp : anexp,
        loc : loc
      }
    | (*%
       * @format({resultVar, codeExp, closureEnvExp: clsEnv clsEnvOpt,
       *          argExpList: arg args, nextExp, handler: handle handleOpt,
       *          loc})
       * L8{ resultVar +d "=" 1[
       *   +1 "call"
       *   +1 codeExp
       *   +1 clsEnvOpt(clsEnv)(,)
       *   +1 args:appList(arg)("(",",",")")
       *   handleOpt(handle)(+1 "handle" +d,)
       *   ";"
       * ] }
       * +1 nextExp
       *)
      (*%
       * @prefix formatWithType_
       * @format({resultVar, codeExp, closureEnvExp: clsEnv clsEnvOpt,
       *          argExpList: arg args, nextExp, handler: handle handleOpt,
       *          loc})
       * L8{ resultVar +d "=" 1[
       *   +1 "call"
       *   +1 codeExp
       *   +1 clsEnvOpt(clsEnv)(,)
       *   +1 args:appList(arg)("(",",",")")
       *   handleOpt(handle)(+1 "handle" +d,)
       *   ";"
       * ] }
       * +1 nextExp
       *)
      ANCALL of
      {
        resultVar : varInfo,
        codeExp : anvalue,
        closureEnvExp : anvalue option,
        argExpList : anvalue list,
        handler : HandlerLabel.id option,
        nextExp : anexp,
        loc : loc
      }
    | (*%
       * @format({resultTy, codeExp, closureEnvExp: clsEnv clsEnvOpt,
       *          argExpList: arg args, loc})
       * L8{ 1[
       *   +1 "tail call"
       *   +1 codeExp
       *   +1 clsEnvOpt(clsEnv)(,)
       *   +1 args:appList(arg)("(",",",")")
       *   ";"
       * ] }
       *)
      (*%
       * @prefix formatWithType_
       * @format({resultTy, codeExp, closureEnvExp: clsEnv clsEnvOpt,
       *          argExpList: arg args, loc})
       * L8{ 1[
       *   +1 "tail call"
       *   +1 codeExp
       *   +1 clsEnvOpt(clsEnv)(,)
       *   +1 args:appList(arg)("(",",",")")
       *   ";"
       * ] }
       *)
      ANTAILCALL of
      {
        resultTy : ty,
        codeExp : anvalue,
        closureEnvExp : anvalue option,
        argExpList : anvalue list,
        loc : loc
      }
    | (*%
       * @format({resultVar, fieldList: field fields,
       *          isMutable, clearPad, allocSizeExp,
       *          bitmaps: bm bms,
       *          nextExp, loc})
       * L8{ resultVar +d "=" 1[
       *   +1 "{"
       *   L2{ !N0{ fields:enclosedList(field)("{",",","}") }
       *       +1 "/t" +d allocSizeExp
       *       +1 "/b" +d bms:appList(bm)("(",",",")") }
       *   "}"
       *   ";"
       * ] }
       * +1 nextExp
       * @format:field({fieldExp, fieldTy, fieldIndex})
       * L2{ "#" +d fieldIndex }
       * +d "=" 1[ +1 fieldExp ]
       * @format:bm({bitmapIndex, bitmapExp})
       * L8{ "[" !N0{ bitmapIndex "]" }
       *     +1 bitmapExp }
       *)
      (*%
       * @prefix formatWithType_
       * @format({resultVar, fieldList: field fields,
       *          isMutable, clearPad, allocSizeExp,
       *          bitmaps: bm bms,
       *          nextExp, loc})
       * L8{ resultVar +d "=" 1[
       *   +1 "{"
       *   L2{ !N0{ fields:enclosedList(field)("{",",","}") }
       *       +1 "/t" +d allocSizeExp
       *       +1 "/b" +d bms:appList(bm)("(",",",")") }
       *   "}"
       *   ";"
       * ] }
       * +1 nextExp
       * @format:field({fieldExp, fieldTy, fieldIndex})
       * L2{ "#" +d fieldIndex }
       * +d "=" 1[ +1 fieldExp ]
       * @format:bm({bitmapIndex, bitmapExp})
       * L8{ "[" !N0{ bitmapIndex "]" }
       *     +1 bitmapExp }
       *)
      ANRECORD of
      {
        resultVar : varInfo,
        fieldList : {fieldExp : initField,
                     fieldTy : ty,
                     fieldIndex : anvalue} list,
        isMutable : bool,
        clearPad : bool,
        allocSizeExp : anvalue,
        bitmaps : {bitmapIndex : anvalue,
                   bitmapExp : anvalue} list,
        nextExp : anexp,
        loc : loc
      }
    | (*%
       * @format({resultVar, recordExp, indexExp, valueExp, valueTy, nextExp,
       *          loc})
       * L8{ resultVar +d "=" 1[
       *   +1 "modify"
       *   +1 recordExp
       *   +1 L2{ "#" +d indexExp }
       *   +1 valueExp
       *   ";"
       * ] }
       * +1 nextExp
       *)
      (*%
       * @prefix formatWithType_
       * @format({resultVar, recordExp, indexExp, valueExp, valueTy, nextExp,
       *          loc})
       * L8{ resultVar +d "=" 1[
       *   +1 "modify"
       *   +1 recordExp
       *   +1 L2{ "#" +d indexExp }
       *   +1 valueExp
       *   ";"
       * ] }
       * +1 nextExp
       *)
      ANMODIFY of
      {
        resultVar : varInfo,
        recordExp : anvalue,
        indexExp : anvalue,
        valueExp : initField,
        valueTy : ty,
        nextExp : anexp,
        loc : loc
      }
    | (*%
       * @format({value, ty, loc})
       * L8{ 1[
       *   "return"
       *   +1 value
       *   ";"
       * ] }
       *)
      (*% @prefix formatWithType_
       * @format({value, ty, loc})
       * L8{ 1[
       *   "return"
       *   +1 L2{ value +d ":" +1 ty }
       *   ";"
       * ] }
       *)
      ANRETURN of
      {
        value : anvalue,
        ty : ty,
        loc : loc
      }
    | (*%
       * @format({srcExp, dstAddr, valueSize, nextExp, loc})
       * L8{ 1[
       *   "copy"
       *   +1 srcExp
       *   +1 dstAddr
       *   +1 valueSize
       *   ";"
       * ] }
       * +1 nextExp
       *)
      (*% @prefix formatWithType_
       * @format({srcExp, dstAddr, valueSize, nextExp, loc})
       * L8{ 1[
       *   "copy"
       *   +1 srcExp
       *   +1 dstAddr
       *   +1 valueSize
       *   ";"
       * ] }
       * +1 nextExp
       *)
      ANCOPY of
      {
        srcExp : anvalue,
        dstAddr : address,
        valueSize : anvalue,
        nextExp : anexp,
        loc : loc
      }
    | (*%
       * @format({srcExp, srcTy, dstAddr, nextExp, loc})
       * L8{ 1[
       *   "store"
       *   +1 srcExp
       *   +1 dstAddr
       *   ";"
       * ] }
       * +1 nextExp
       *)
      (*% @prefix formatWithType_
       * @format({srcExp, srcTy, dstAddr, nextExp, loc})
       * L8{ 1[
       *   "store"
       *   +1 srcExp
       *   +1 dstAddr
       *   ";"
       * ] }
       * +1 nextExp
       *)
      ANSTORE of
      {
        srcExp : anvalue,
        srcTy : ty,
        dstAddr : address,
        nextExp : anexp,
        loc : loc
      }
    | (*%
       * @format({id, ty, valueExp, nextExp, loc})
       * L8{ 1[
       *   "export"
       *   +1 "@ext:" id
       *   +1 valueExp
       *   ";"
       * ] }
       * +1 nextExp
       *)
      (*% @prefix formatWithType_
       * @format({id, ty, valueExp, nextExp, loc})
       * L8{ 1[
       *   "export"
       *   +1 "@ext:" id
       *   +1 valueExp
       *   ";"
       * ] }
       * +1 nextExp
       *)
      ANEXPORTVAR of
      {
        id : ExternSymbol.id,
        ty : ty,
        valueExp : anvalue,
        nextExp : anexp,
        loc : loc
      }
    | (*%
       * @format({argExp, cleanup: cleanup cleanupOpt, loc})
       * L8{ 1[
       *   "raise"
       *   +1 argExp
       *   +1 cleanupOpt(cleanup)(+1 "cleanup" +d,)
       *   ";"
       * ] }
       *)
      (*% @prefix formatWithType_
       * @format({argExp, cleanup: cleanup cleanupOpt, loc})
       * L8{ 1[
       *   "raise"
       *   +1 argExp
       *   +1 cleanupOpt(cleanup)(+1 "cleanup" +d,)
       *   ";"
       * ] }
       *)
      ANRAISE of
      {
        argExp : anvalue,
        cleanup : HandlerLabel.id option,
        loc : loc
      }
    | (*%
       * @format({nextExp, exnVar, id, handlerExp, cleanup: cleanup cleanupOpt,
       *          loc})
       * L8{ 1[ "try" +1 id ] }
       * +1 nextExp
       * +1 L8{ 1[ "handle" +1 id d +1 exnVar +d "=" ] }
       * +1 handlerExp 
       * cleanupOpt(cleanup)(+1 "cleanup" +d,)
       *)
      (*% @prefix formatWithType_
       * @format({nextExp, exnVar, id, handlerExp, cleanup: cleanup cleanupOpt,
       *          loc})
       * L8{ 1[ "try" +1 id ] }
       * +1 nextExp
       * +1 L8{ 1[ "handle" +1 id d +1 exnVar +d "=" ] }
       * +1 handlerExp
       * cleanupOpt(cleanup)(+1 "cleanup" +d,)
       *)
      ANHANDLER of
      {
        nextExp : anexp,
        id : HandlerLabel.id,
        exnVar : varInfo,
        handlerExp : anexp,
        cleanup : HandlerLabel.id option,
        loc : loc
      }
    | (*%
       * @format({switchExp, expTy, branches: branch branches, default, loc})
       * L8{ 1[
       *   "case"
       *   +1 switchExp
       *   +1 "of"
       * ] }
       * branches:caseList(branch)
       *   (2[+1], +1 "|" +d, !N0{ "_" +d "=>" +1 "@L:" default })
       * @format:branch(constant * branchId)
       * !N0{ constant +d "=>" +1 "@L:" branchId }
       *)
      (*% @prefix formatWithType_
       * @format({switchExp, expTy, branches: branch branches, default, loc})
       * L8{ 1[
       *   "case"
       *   +1 switchExp
       *   +1 "of"
       * ] }
       * branches:caseList(branch)
       *   (2[+1], +1 "|" +d, !N0{ "_" +d "=>" +1 "@L:" default })
       * @format:branch(constant * branchId)
       * !N0{ constant +d "=>" +1 "@L:" branchId }
       *)
      ANSWITCH of
      {
        switchExp : anvalue,
        expTy : ty,
        branches : (anconst * FunLocalLabel.id) list,
        default : FunLocalLabel.id,
        loc : loc
      }
    | (*%
       * @format({id, recursive, argVarList : arg args, bodyExp, nextExp, loc})
       * L8{ 1[
       *   "available"
       *   +1 "@L:" id
       *   ";"
       * ] }
       * +1 nextExp
       * +1
       * L8{ 1[
       *   recursive()("rec" +d,)
       *   "@L:" id
       *   +1 args:appList(arg)("(",",",")")
       *   +d "="
       * ] }
       * +1 bodyExp
       *)
      (*% @prefix formatWithType_
       * @format({id, recursive, argVarList : arg args, bodyExp, nextExp, loc})
       * L8{ 1[
       *   "available"
       *   +1 "@L:" id
       *   ";"
       * ] }
       * +1 nextExp
       * +1
       * L8{ 1[
       *   recursive()("rec" +d,)
       *   "@L:" id
       *   +1 args:appList(arg)("(",",",")")
       *   +d "="
       * ] }
       * +1 bodyExp
       *)
      ANLOCALCODE of
      {
        id : FunLocalLabel.id,
        recursive : bool,
        argVarList : varInfo list,
        bodyExp : anexp,
        nextExp : anexp,
        loc : loc
      }
    | (*%
       * @format({id, argList: arg args, loc})
       * L8{ 1[
       *   "goto"
       *   +1 "@L:" id
       *   +1 args:appList(arg)("(",",",")")
       *   ";"
       * ] }
       *)
      (*% @prefix formatWithType_
       * @format({id, argList: arg args, loc})
       * L8{ 1[
       *   "goto"
       *   +1 "@L:" id
       *   +1 args:appList(arg)("(",",",")")
       *   ";"
       * ] }
       *)
      ANGOTO of
      {
        id : FunLocalLabel.id,
        argList : anvalue list,
        loc : loc
      }
    | (*%
       * @format
       * "unreachable;"
       *)
      (*% @prefix formatWithType_
       * @format
       * "unreachable;"
       *)
      ANUNREACHABLE   (* control never reaches here *)

  (*%
   * @formatter(RuntimeCalc.topdata) RuntimeCalc.format_topdata
   *)
  (*% @prefix formatWithType_
   * @formatter(RuntimeCalc.topdata) RuntimeCalc.formatWithType_topdata
   *)
  datatype topdata = datatype RuntimeCalc.topdata

  (*%
   * @formatter(option) SmlppgUtil.formatOptWithDefault
   * @formatter(optional) TermFormat.formatOptionalOption
   * @formatter(FunEntryLabel.id) FunEntryLabel.format_id
   * @formatter(CallbackEntryLabel.id) CallbackEntryLabel.format_id
   * @formatter(HandlerLabel.id) HandlerLabel.format_id
   * @formatter(appList) TermFormat.formatAppList
   *)
  (*%
   * @prefix formatWithType_
   * @formatter(option) SmlppgUtil.formatOptWithDefault
   * @formatter(optional) TermFormat.formatOptionalOption
   * @formatter(FunEntryLabel.id) FunEntryLabel.format_id
   * @formatter(CallbackEntryLabel.id) CallbackEntryLabel.format_id
   * @formatter(HandlerLabel.id) HandlerLabel.format_id
   * @formatter(appList) TermFormat.formatAppList
   *)
  datatype topdec =
      (*%
       * @format({id, tyvarKindEnv, argVarList: arg args,
       *          closureEnvVar: env envOpt, bodyExp, retTy, gcCheck, loc})
       * "@fun:" id
       * + envOpt(env)("_")
       * + args:appList(arg)("(",",",")")
       * + "="
       * 1[ +1 bodyExp ]
       *)
      (*% @prefix formatWithType_
       * @format({id, tyvarKindEnv, argVarList: arg args,
       *          closureEnvVar: env envOpt, bodyExp, retTy, gcCheck, loc})
       * "@fun:" id
       * + envOpt(env)("_")
       * + args:appList(arg)("(",",",")")
       * + "="
       * 1[ +1 bodyExp ]
       *)
      ATFUNCTION of
      {
        id : FunEntryLabel.id,
        tyvarKindEnv : Types.btvEnv,
        argVarList : varInfo list,
        closureEnvVar : varInfo option,
        bodyExp : anexp,
        retTy : ty,
        gcCheck : bool,
        loc : loc
      }
    | (*%
       * @format({id, tyvarKindEnv, argVarList: arg args,
       *          closureEnvVar: env envOpt, bodyExp, attributes, retTy,
       *          cleanupHandler: cleanup cleanupOpt, loc})
       * "@callback:" id
       * + envOpt(env)("_")
       * + args:appList(arg)("(",",",")")
       * + cleanupOpt:optional(cleanup)("cleanup" +,)
       * + "="
       * 1[ +1 bodyExp ]
       *)
      (*% @prefix formatWithType_
       * @format({id, tyvarKindEnv, argVarList: arg args,
       *          closureEnvVar: env envOpt, bodyExp, attributes, retTy,
       *          cleanupHandler: cleanup cleanupOpt, loc})
       * "@callback:" id
       * + envOpt(env)("_")
       * + args:appList(arg)("(",",",")")
       * + cleanupOpt:optional(cleanup)("cleanup" +,)
       * + "="
       * 1[ +1 bodyExp ]
       *)
      ATCALLBACKFUNCTION of
      {
        id : CallbackEntryLabel.id,
        tyvarKindEnv : Types.btvEnv,
        argVarList : varInfo list,
        closureEnvVar : varInfo option,
        bodyExp : anexp,
        attributes : FFIAttributes.attributes,
        retTy : ty option,
        cleanupHandler : HandlerLabel.id option,
        loc : loc
      }

  (*%
   * @formatter(decList) TermFormat.formatDeclList
   * @formatter(option) TermFormat.formatOptionalOption
   * @formatter(HandlerLabel.id) HandlerLabel.format_id
   *)
  (*% @prefix formatWithType_
   * @formatter(decList) TermFormat.formatDeclList
   * @formatter(option) TermFormat.formatOptionalOption
   * @formatter(HandlerLabel.id) HandlerLabel.format_id
   *)
  type program =
      (*%
       * @format({topdata: datum data, topdecs: dec decs, topExp,
       *          topCleanupHandler: cleanup cleanupOpt})
       * "_decl"
       * 1[ data:decList(datum)(+1,+1) ]
       * 1[ decs:decList(dec)(+1,+1) ]
       * +1 "in" 1[ +1 !N0{ topExp } ]
       * +1 "end"
       * +1 cleanupOpt(cleanup)("cleanup" +,)
       *)
      (*% @prefix formatWithType_
       * @format({topdata: datum data, topdecs: dec decs, topExp,
       *          topCleanupHandler: cleanup cleanupOpt})
       * "_decl"
       * 1[ data:decList(datum)(+1,+1) ]
       * 1[ decs:decList(dec)(+1,+1) ]
       * +1 "in" 1[ +1 !N0{ topExp } ]
       * +1 "end"
       * +1 cleanupOpt(cleanup)("cleanup" +,)
       *)
      {
        topdata : topdata list,
        topdecs : topdec list,
        topExp : anexp,
        topCleanupHandler : HandlerLabel.id option
      }

end
